<?php

namespace delayQueue;

// Ensure the Redis extension is loaded
if (!class_exists('Redis', false)) {
    throw new \Exception('Redis extension is not installed or loaded');
}

// 注册自动加载函数，确保Redis类能被正确加载
spl_autoload_register(function($class) {
    if ($class === 'Redis') {
        return true; // Redis是PHP扩展，不是普通类文件
    }
});

class DelayQueue
{
    protected $redis = null;
    protected $key = 'redis_plan';

    public function __construct($key = '')
    {
        if ($key) $this->key = $key;
        
        $this->initRedis();
    }
    
    /**
     * 初始化Redis连接
     * 配置持久连接和更长的超时时间，增加稳定性
     */
    protected function initRedis()
    {
        try {
            // 直接使用字符串形式实例化Redis类，避免命名空间解析问题
            $redisClassName = 'Redis';
            $this->redis = new $redisClassName();
            $config = [
                'host' => '127.0.0.1',
                'port' => 6379,
                'auth' => '',
                'timeout' => 3600, // 增加超时时间到1小时
            ];
            
            // 使用connect替代pconnect，避免Windows环境下的持久连接问题
            // 在Windows下，pconnect可能导致连接不稳定
            $connected = $this->redis->connect($config['host'], $config['port'], $config['timeout']);
            
            if (!$connected) {
                throw new \Exception('无法连接到Redis服务器: ' . $config['host'] . ':' . $config['port']);
            }
            
            // 如果有密码，则进行认证
            if (!empty($config['auth'])) {
                $authResult = $this->redis->auth($config['auth']);
                if (!$authResult) {
                    throw new \Exception('Redis认证失败');
                }
            }
            
            // 使用try-catch包装setOption调用，防止不支持的选项导致异常
            try {
                // 设置TCP保活选项
                if (defined('\Redis::OPT_TCP_KEEPALIVE')) {
                    $this->redis->setOption(\Redis::OPT_TCP_KEEPALIVE, 60);
                } else {
                    // 尝试使用数值常量
                    $this->redis->setOption(11, 60); // 11 对应 Redis::OPT_TCP_KEEPALIVE
                }
                
                // 设置序列化器，提高数据处理效率
                if (defined('\Redis::SERIALIZER_PHP')) {
                    $this->redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP);
                }
            } catch (\Exception $e) {
                // 记录警告但不中断执行
                error_log('设置Redis选项时发生警告: ' . $e->getMessage());
            }
        } catch (\Exception $e) {
            throw new \Exception('Redis队列初始化失败: ' . $e->getMessage());
        }
    }
    
    /**
     * 检查Redis连接状态，如果断开则尝试重新连接
     */
    protected function checkAndReconnect()
    {
        try {
            // 尝试一个简单的命令来检查连接状态
            if (method_exists($this->redis, 'ping')) {
                $pingResult = $this->redis->ping();
                return $pingResult === '+PONG' || $pingResult === true;
            } else {
                // 备选方法：尝试获取当前时间
                $this->redis->time();
                return true;
            }
        } catch (\Exception $e) {
            // 连接断开，尝试重新连接
            $this->initRedis();
            return true;
        }
    }

    public function delTask($value)
    {
        try {
            // 检查连接状态
            $this->checkAndReconnect();
            return $this->redis->zRem($this->key, $value);
        } catch (\Exception $e) {
            // 发生错误时尝试重新连接并重试
            $this->initRedis();
            return $this->redis->zRem($this->key, $value);
        }
    }

    public function getTask()
    {
        try {
            // 检查连接状态
            $this->checkAndReconnect();
            //获取任务，以0和当前时间为区间，返回一条记录
            return $this->redis->zRangeByScore($this->key, 0, time(), ['limit' => [0, 10]]);
        } catch (\Exception $e) {
            // 发生错误时尝试重新连接并重试
            $this->initRedis();
            return $this->redis->zRangeByScore($this->key, 0, time(), ['limit' => [0, 10]]);
        }
    }

    public function addTask($name, $time, $data)
    {
        try {
            // 检查连接状态
            $this->checkAndReconnect();
            //添加任务，以时间作为score，对任务队列按时间从小到大排序
            return $this->redis->zAdd(
                $this->key,
                $time,
                json_encode(
                    [
                        'task_name' => $name,
                        'task_time' => $time,
                        'task_params' => $data,
                    ], JSON_UNESCAPED_UNICODE
                )
            );
        } catch (\Exception $e) {
            // 发生错误时尝试重新连接并重试
            $this->initRedis();
            return $this->redis->zAdd(
                $this->key,
                $time,
                json_encode(
                    [
                        'task_name' => $name,
                        'task_time' => $time,
                        'task_params' => $data,
                    ], JSON_UNESCAPED_UNICODE
                )
            );
        }
    }

}